using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using Microsoft.BizTalk.TransportProxy.Interop;
using Microsoft.BizTalk.Message.Interop;

namespace Microsoft.Samples.BizTalk.Adapter.Tcp.Receive
{
    /// <summary>
    ///     This class implements a transmitter that is called by BizTalk when returning responses.
    /// </summary>
    /// <author>
    ///     Paul Brown
    /// </author>
    public partial class Transmitter : IBTTransmitter
    {
        #region Private Static Members

        private static List<Transmitter>    _handlers;          // An array of the transmitter handlers
        private static object               _lockObject;        // The lock object for the array of handlers

        #endregion

        #region Private Instance Members

        private IAdapter                    _adapter;           // The adapter
        private ReceiveLocation             _receiveLocation;   // A reference to the receive location
        private Socket                      _clientSocket;      // The client socket waiting for the response
        private AutoResetEvent              _waitEvent;         // The wait object used to wait for the response

        #endregion

        #region Constructor - Static

        /// <summary>
        ///     This type constructor initializes the type.
        /// </summary>
        static Transmitter()
        {
            Transmitter._handlers = new List<Transmitter>();
            Transmitter._lockObject = new object();
        }

        #endregion

        #region Constructor - Instance

        /// <summary>
        ///     This constructor accepts a reference to the adapter and receive location as well as the client socket that the response
        ///     will be returned down.
        /// </summary>
        public Transmitter(IAdapter adapter, ReceiveLocation receiveLocation, Socket clientSocket)
        {
            // Validate
            if (adapter == null) throw new ArgumentNullException("adapter");
            if (receiveLocation == null) throw new ArgumentNullException("receiveLocation");
            if (clientSocket == null) throw new ArgumentNullException("clientSocket");

            // Initialize members
            this._adapter = adapter;
            this._receiveLocation = receiveLocation;
            this._clientSocket = clientSocket;
            this._waitEvent = new AutoResetEvent(false);
        }

        #endregion

        #region Public Instance Properties

        /// <summary>
        ///     This property returns a reference to the adapter.
        /// </summary>
        public IAdapter Adapter
        {
            get { return (this._adapter); }
        }

        /// <summary>
        ///     This property returns a reference to the receive location.
        /// </summary>
        public ReceiveLocation ReceiveLocation
        {
            get { return (this._receiveLocation); }
        }

        /// <summary>
        ///     This property returns the client socket that is waiting for the response message.
        /// </summary>
        public Socket ClientSocket
        {
            get { return (this._clientSocket); }
        }

        #endregion

        #region Public Static Methods

        /// <summary>
        ///     This method adds a transmitter handler to the type.
        /// </summary>
        public static void AddHandler(Transmitter transmitterHandler)
        {
            lock (Transmitter._lockObject)
            {
                Transmitter._handlers.Add(transmitterHandler);
            }
        }

        /// <summary>
        ///     This method removes a transmitter handler from the type.
        /// </summary>
        public static void RemoveHandler(Transmitter transmitterHandler)
        {
            lock (Transmitter._lockObject)
            {
                Transmitter._handlers.Remove(transmitterHandler);
            }
        }

        #endregion

        #region Public Instance Methods

        /// <summary>
        ///     This method causes the caller to wait for the response.  Useful in an ordered delivery scenario.
        /// </summary>
        public void WaitForResponse()
        {
            // Wait for event to be signalled
            this._waitEvent.WaitOne();
        }

        #endregion
    }
}
